/**
* @file SDLresource.cpp
* Wrapper class created to easily work with SDL
* @author Timmy Nelen
* @date 21/11/2010
*/

#include "SDLResource.h"

/**
 * (Empty) Constructor
 */
bo_sdl::SDLResource::SDLResource(){}

/**
 * Destructor of the SDLResource object
 */
bo_sdl::SDLResource::~SDLResource() {
	delete fBackground;
	SDL_FreeSurface(fScreen);
	SDL_Quit();
	delete fScreen;
	delete fInstance;
	delete fPow;
}

bo_sdl::SDLResource* bo_sdl::SDLResource::fInstance = NULL;

/**
 * Returns the current instance of the screen. Self-initializes iff no screen found
 *
 * @return The instance of the SDLResource object
 */
bo_sdl::SDLResource* bo_sdl::SDLResource::Instance(){
	if (fInstance == NULL){
		fInstance = new SDLResource;
	}
	return fInstance;
}

/**
 * Initializes the SDL Layer using the supplied screen size
 *
 * @param[in] xScreen The width of the screen to be used
 * @param[in] yScreen The height of the screen to be used
 * @param[in] scale The scale to be used
 * @param[in] bgFile The filename of the background to be used
 * @param[in] powFile The filename of the powfile to be used
 *
 * @return True if initialization succeeded
 */
bool bo_sdl::SDLResource::Initialize(int xScreen, int yScreen, double scale, const char* bgFile, const char* powFile){

	if (SDL_Init(SDL_INIT_VIDEO) == -1)
		return false;
	if (SDL_Init(SDL_INIT_AUDIO) == -1)
		return false;
	if (TTF_Init() == -1)
		return false;
	fScreen = SDL_SetVideoMode(xScreen, yScreen, 24, SDL_DOUBLEBUF);
	if (!fScreen)
		return false;
	this->fScale = scale;
	this->fBackground = IMG_Load(bgFile);
	if ( !this->fBackground )
		return false;
	this->fPow = IMG_Load(powFile);
	if ( !this->fPow )
		return false;
	return true;
}
/**
 * Blit the used sprite (fSprite) on the screen
 *
 * @param[in] img The image to be blitted onto the screen
 * @param[in] pos The position where the image has to be blitted
 */
void bo_sdl::SDLResource::BlitToScreen(SDL_Surface* img, Vector2 pos){
	if ( !this->fBGBlitted ){
		this->BlitBackground();
		this->fBGBlitted = true;
	}
	SDL_Rect dest;
	dest.x = pos.GetX();
	dest.y = pos.GetY();
	dest.w = img->w;
	dest.h = img->h;
	// src = null -> blit entire sprite on screen
	SDL_BlitSurface(img, NULL, fScreen, &dest);
}

/**
 * Returns the scale, to be used in the visualize methods
 *
 * @return The scale of the screen
 */

double bo_sdl::SDLResource::GetScale(){
	return this->fScale;
}

/**
 * Sets the background sprite to be used
 *
 * @param[in] fileName The filename of the background to be used
 */

void bo_sdl::SDLResource::SetBackground(const char* fileName){
	this->fBackground = IMG_Load(fileName);
}

/**
 * Blits the background on the screen
 */

void bo_sdl::SDLResource::BlitBackground(){
	SDL_Rect dest;
	dest.x = 0;
	dest.y = 0;
	dest.w = this->fBackground->w;
	dest.h = this->fBackground->h;
	SDL_BlitSurface(this->fBackground, NULL, this->fScreen, &dest);
}
/**
 * Flips the screen
 */
void bo_sdl::SDLResource::FlipScreen(){
	SDL_Flip(fScreen);
}

/**
 * Clears the back buffer, fills it with black
 */
void bo_sdl::SDLResource::ClearBackBuffer(){
	SDL_FillRect(fScreen, 0, 0);
	this->fBGBlitted = false;
}

/**
 * Draws a thin black rectangle for the HUD (to contain the playername, score, ...)
 */
void bo_sdl::SDLResource::DrawHUDRect(){
    SDL_Surface* surface = SDL_CreateRGBSurface(SDL_SWSURFACE, 8 * this->fScale,0.25 * this->fScale,32,0,0,0,0);
    Vector2 tempPos(0, 5.75 * this->fScale);
	BlitToScreen(surface, tempPos);
	delete surface;
}

/**
 * Draws the supplied text to the supplied position on the screen
 *
 * @param[in] string The string to be put on the screen
 * @param[in] x The X position of the text
 * @param[in] y The Y position of the text
 */

void bo_sdl::SDLResource::DrawText(const char* string, const double x, const double y){
	SDL_Surface* text;
	if ( this->fFont == 0 )
		this->fFont = TTF_OpenFont( "stdFont.ttf", 20 );
	SDL_Color textColor = { 255, 255, 255 };
	text = TTF_RenderText_Solid( this->fFont, string, textColor );
	Vector2 tempPos(x*this->fScale, y*this->fScale);
	BlitToScreen(text, tempPos);
	delete text;
}

/**
 * Shows the menu. Only exits this function when the user presses enter. Keeps track of what menu option was chosen
 *
 * @param[in,out] returnvalue The value which is returned after the processing of the menu
 */

void bo_sdl::SDLResource::ShowMenu(int& returnValue){
	Uint8* keyState = SDL_GetKeyState(0);
	SDL_PumpEvents();
	SDL_Surface* tempBG = this->fBackground;
	this->fBackground = IMG_Load("stdMenu.jpg");
	SDL_Surface* arrow = IMG_Load("arrow.png");
	Vector2 arrPos(-0.05, 4.55 * fScale);
	returnValue = 0;
	// Temporarily load a bigger font for the menu
	this->fFont = TTF_OpenFont( "font.ttf", 50 );
	while ( !keyState[SDLK_RETURN] ){
		DrawText("Play", 0.3, 4.6);
		DrawText("Help", 0.3, 5.0);
		DrawText("Quit", 0.3, 5.4);
		BlitToScreen(arrow, arrPos);
		FlipScreen();
		ClearBackBuffer();
		SDL_PumpEvents();
		keyState = SDL_GetKeyState(0);
		if ( keyState[SDLK_DOWN] && returnValue < 2){
			arrPos.SetY(arrPos.GetY() + 0.4 * fScale);
			++returnValue;
			while ( keyState[SDLK_DOWN] )
				SDL_PumpEvents();
		}
		if ( keyState[SDLK_UP] && returnValue > 0){
			arrPos.SetY(arrPos.GetY() - 0.4 * fScale);
			--returnValue;
			while ( keyState[SDLK_UP] )
				SDL_PumpEvents();
		}
	}
	// restore original BG and fonts
	this->fBackground = tempBG;
	this->fFont = TTF_OpenFont( "font.ttf", 20 );
	delete arrow;
	return;
}

/**
 * Shows the instructions on the screen, returns to the main screen once ESCAPE is pressed
 */
void bo_sdl::SDLResource::ShowHelpMenu(){
	// Save previous background, as we just need a black screen for the help menu
	SDL_Surface* tempBG = this->fBackground;
	// Create a temp black screen as background
    this->fBackground = SDL_CreateRGBSurface(SDL_SWSURFACE, 8 * this->fScale,6 * this->fScale,32,0,0,0,0);
    // Temp. increase the font size
	SDL_FillRect(fScreen, 0, 0);
	DrawText("Instructions:", 0, 0);
	DrawText("Move the paddle from left to right using the arrow keys.", 0, 0.2);
	DrawText("You start the game with 5 lives", 0, 1.2);
	DrawText("If the ball leaves the bottom of the screen, you lose a life", 0, 1.4);
	DrawText("Once you lose all 5 of your lives, you lose the game", 0, 1.6);
	DrawText("The ultimate goal of the game is to destroy all the blocks ", 0, 1.8);
	DrawText("at the top of the screen", 0.5, 2.0);
	DrawText("Press escape to return to the menu and pause the game", 0, 2.2);
	DrawText("Press ESCAPE to return to the main screen", 0, 2.7);
	Vector2 tempPos(5 * fScale, 0.45 * fScale);
	BlitToScreen(IMG_Load("arrowpng.png"), tempPos);
	tempPos.SetX(425);
	BlitToScreen(IMG_Load("arrowpngleft.png"), tempPos);
	FlipScreen();
	Uint8* keyState = SDL_GetKeyState(0);
	SDL_PumpEvents();
	while ( !keyState[SDLK_ESCAPE] ){
		SDL_PumpEvents();
		if ( keyState[SDLK_ESCAPE] ){
			this->fBackground = tempBG;
			return;
		}
	}
}

/**
 * Returns the pow sprite, to be used in the SDLBall destructor
 *
 * @return Pointer to SDL_Surface containing the pow sprite
 */

SDL_Surface* bo_sdl::SDLResource::GetPow(){
	return fPow;
}
